
#include "copyright.h"
#include "system.h"
#include "iostream.h"
#include "thread.h"
#include "list.h"
#include "synch.h"
#include "Assignment1.h"
#include "mipssim.h"

/*
 * This function Initializes all the variables neede for receptionist
 *
 *
 */


void InitilalizeRecep(int number){

    Num_of_receptionist=number;
    //for test scenario only
    if (number ==-1)
        Num_of_receptionist=1;

    ConsultancyLock = new Lock("ConsultancyLock");

    pharmacyTotal = 0;
    pharmacyTotalLock = new Lock("pharmacyTotalLock");

    cashierTotal = 0;
    cashierTotalLock = new Lock("cashierTotalLock");

    RecpLineLock = new Lock("RecLineLock");
    arr_RecLineCount = new int[Num_of_receptionist];
    arr_RecLineCV = new Condition *[Num_of_receptionist];
    arr_RecCV = new Condition *[Num_of_receptionist];
    RecepLock = new Lock *[Num_of_receptionist];
    RecToken = new int[Num_of_receptionist];
    tokenLock = new Lock("Lock_Token");
    RecBreakLock = new Lock("RecepBreakLock");
    RecbreakCV = new Condition("RecbreakCV");

    char* name_cond;
    char* name_lock;
    char* name_cond1;
    currentToken = 0;
    //Initially line count for all receptionist is 0
    for(int i=0; i< Num_of_receptionist; i++)
    {
        name_cond = new char [20];
        name_lock = new char [20];
        name_cond1 = new char [20];

        sprintf(name_cond,"RecepCV_%d",i);
        sprintf(name_lock,"RecepLock_%d",i);
        sprintf(name_cond1,"RecepCV1_%d",i);

        arr_RecLineCount[i] = 0;

        arr_RecLineCV[i] = new Condition(name_cond);
        RecepLock[i] = new Lock(name_lock);
        arr_RecCV[i] = new Condition(name_cond1);
        RecToken[i] = 0;

    }

    //for test scenario only
    if (number ==-1)
        Num_of_receptionist=0;


}

/*
 * This function Initializes all the variables neede for DoorBoy
 *
 *
 */


//This function prepares the Door Boys
void InitializeDB(int noOfDB){
    int numberOfDoorBoy = noOfDB;
    numOfDoctors = numberOfDoorBoy;

    arr_DoctorLineCount = new int[numberOfDoorBoy];   //this tracks the number of patient in the doctors line
    DBLineLock = new Lock("DoorBoyLock") ;       //Lock for the doorboy line
    arr_DoctorLineCV = new Condition *[numberOfDoorBoy];
   // arr_DBOnBreak =  new int[numberOfDoorBoy];      //0 - break; 1 - Not on break
    Doctor_DB = new int[numberOfDoorBoy];
    DoorBoyLock = new Lock("DoorBoyLock");

    char* name_cond;
    char* name_lock;

    for(int i=0; i< numberOfDoorBoy; i++)
    {
        name_cond = new char [20];
        name_lock = new char [20];

        sprintf(name_cond,"DBCV_%d",i);
        sprintf(name_lock,"DBLock_%d",i);


        arr_DoctorLineCount[i] = 0;
        arr_DoctorLineCV[i] = new Condition(name_cond);
        //DBLineLock[i] = new Lock(name_lock);

       // arr_DBOnBreak[i] = 1;
        Doctor_DB[i] = -1;

    }

}

void InitializePatient(int number)
{
    arr_ConsultancyFee = new int [number];
    for(int i =0; i<number;i++)
        arr_ConsultancyFee[i] = 100;
}

/*
 * This function Initializes all the variables neede for Doctor
 *
 *
 */
void InitializeDoctor(int number){

     arr_DoctorCV = new Condition *[number];
     arr_DoctorLock = new Lock *[number];
    arr_DoctorOnBreak = new int[number]; //-1 - on break, 1 - not on break
    Doc_PrescriptionLock =  new Lock("Doc_Pres_Lock");
    Prescription = new int[number];    //-1 indicates no prescription ready
    DocBreakLock = new Lock("Doc Break lock");
    Doctor_DoorBoyCV = new Condition *[number];
    Doctor_DoorBoyLock = new Lock *[number];
    Doctor_Token = new int [number];

     char* name_cond;
    char* name_lock;

    for(int i=0; i< number; i++)
    {
        name_cond = new char [20];
        name_lock = new char [20];

        sprintf(name_cond,"DoctorCV_%d",i);
        sprintf(name_lock,"DoctorLock_%d",i);

        arr_DoctorCV[i] = new Condition(name_cond);
        arr_DoctorLock[i] = new Lock(name_lock);
        arr_DoctorOnBreak[i] = 1;
        Prescription[i] = -1;

        sprintf(name_cond,"Doctor_DB_CV_%d",i);
        sprintf(name_lock,"Doctor_DB_Lock_%d",i);

        Doctor_DoorBoyLock[i] = new Lock(name_lock);
        Doctor_DoorBoyCV[i] = new Condition(name_cond);

    }

}

void InitializePharma(int number)
{
    clerks = number;

    //initializing the condition variables and the locks defined
    pharmaLineLock = new Lock("PharmaLineLock");
    PharmacyBreakCV = new Condition("PharmacyBreakCV");
    PharmacyBreakLock = new Lock("PharmacyBreakLock");

    linePharmaSize = new int[clerks];

    clerkCV = new Condition *[clerks];
    patientCV = new Condition *[clerks];

    interactionLock = new Lock *[clerks];
    pharmacyControl = new Condition *[clerks];


    pharmacyFlow = new int [clerks];

    char *name;
    for(int i =0; i <clerks; i++)
    {
        name = new char [20];

        linePharmaSize[i]=0;

        sprintf(name,"pharmacyControl");
        pharmacyControl[i] = new Condition(name);

        sprintf(name,"clerkCV %d",i+1);
        clerkCV[i] = new Condition(name);

        sprintf(name,"patientCV %d",i+1);
        patientCV[i] = new Condition(name);

        sprintf(name,"interactionLock %d",i+1);
        interactionLock[i] = new Lock(name);
    }

}


void InitializeCashier(int number)
{
    //check = 0;
    cashier = number;

    cashierLineLock = new Lock("LineControlLock");

    lineSize = new int[cashier];

    cashierCV = new Condition *[cashier];
    cPatientCV = new Condition *[cashier];

    cashFlow = new int [cashier];

    interactionCashierLock = new Lock *[cashier];

    cashierControl = new Condition *[cashier];

    CashierBreakLock = new Lock("CashierBreakLock");
    CashierBreakCV = new Condition("CashierBreakCV");

    char *name;
    for(int i =0; i <cashier; i++)
    {
        name = new char [20];

        lineSize[i]=0;

        sprintf(name,"cashierControl");
        cashierControl[i] = new Condition(name);

        sprintf(name,"clerkCV %d",i+1);
        cashierCV[i] = new Condition(name);

        sprintf(name,"patientCV %d",i+1);
        cPatientCV[i] = new Condition(name);

        sprintf(name,"interactionCashierLock %d",i+1);
        interactionCashierLock[i] = new Lock(name);
    }

}



//This function simulates the behaviour and characteristics of patient
//@input:  paientid : Id to recognize the patient.
//
void Patient(int patientId){

    int myrecLine, myToken,myDoctor, myDoorBoy,patId,Myprescription;
    patId = patientId;

    cout<<"\n\nThread Name: " << currentThread->getName() <<"\nPatient Id: " <<patientId <<endl;

    //pick the shortest Line
    RecpLineLock->Acquire();                //Acquire Lock to get in the smallest Line

    myrecLine = GetMinValue(arr_RecLineCount,Num_of_receptionist);
    //printf("\nQueue= %d\nPatient= %d\nArr_value=%d\n",myrecLine,patientId,arr_RecLineCount[myrecLine]);
    

    if(arr_RecLineCount[myrecLine] > 0  || arr_RecLineCount[myrecLine] == 0 )  //If line exist, i will wait in line
    {
        //Incrementing the count for that line
        arr_RecLineCount[myrecLine]++;

        cout<<"\n\n***TEST CASE 6***\nDetails-\nPatient Id: "<<patientId<<"\nEntering Line: "<<myrecLine<<"\nLine Size: "<<arr_RecLineCount[myrecLine]<<endl;
        //printf("\nI am increamenting the value!!");

        //going to wait
        (arr_RecLineCV[myrecLine])->Wait(RecpLineLock);

        //when I woke up I am goint to get attended, so dec the line count
     //   cout << "I am waking up \n";
        arr_RecLineCount[myrecLine]--;
       // cout << "\n I am out of line and dec, patient id : "<< patientId <<"\n";
        //cout << "I am abt to release reclinelock \n";
        RecpLineLock->Release();

        //Now I go to the receptioninst - not in line
        RecepLock[myrecLine]->Acquire();

        //signal the receptionist that I am here for a token
        arr_RecCV[myrecLine]->Signal(RecepLock[myrecLine]);

        //wait for the receptionist to give me token
        arr_RecCV[myrecLine]->Wait(RecepLock[myrecLine]);

        //Rec signaled me saying token is ready, So I get my token
        myToken = RecToken[myrecLine];

        cout << "\n\nPatient <-> Receptionist \nPatientId: " <<patId << "\nToken: " <<myToken <<"\nReceptionistId: " <<myrecLine <<endl;

        //signal the receptionist that I have taken the token
        arr_RecCV[myrecLine]->Signal(RecepLock[myrecLine]);

        RecepLock[myrecLine]->Release(); //Interaction with receptionist is over.

        //Now patienst goes to the doctors Q
        DBLineLock-> Acquire();

        //choose the doctor randomly
        myDoctor = GenerateRandomDoctorNumber(numOfDoctors-1, 0);

        //cout << "PatientId :"<< patId <<"has Doctor" << myDoctor << "\n";

        //Fetching the Doorboy to that doctor
        //myDoorBoy = Doctor_DB[myDoctor];

        //Adding myself to the line of the doctor
        arr_DoctorLineCount[myDoctor]++;

        //cout << "I have inc the value to :" << arr_DoctorLineCount[myDoctor] << "\n";

         //I will wait for the door boy to signal me
        arr_DoctorLineCV[myDoctor]->Wait(DBLineLock);


        //when I wake up I get out of the line and acquire Lock of that doctor
        arr_DoctorLineCount[myDoctor]--;

        //cout << "Now I will acquire Doctor Lock" << myDoctor <<"and signal DoorBoy" << myDoorBoy << "\n";
        //cout << "Which has a line length " <<   arr_DoctorLineCount[myDoctor] << "\n";

        arr_DoctorLock[myDoctor]->Acquire();

        //DBLineLock->Release();
        // cout << "Now Patient ID :" << patId << "is ready to see the doctor ID : " << myDoctor << "\n\n";
        arr_DoctorLineCV[myDoctor]->Signal(DBLineLock);
        DBLineLock->Release();

        
        //signal the doctor that I have arrived.
        Doctor_Token[myDoctor] = myToken;

        arr_DoctorCV[myDoctor]->Signal(arr_DoctorLock[myDoctor]);
        
        //wait for the doctor to consult and and get prescription.
        arr_DoctorCV[myDoctor]->Wait(arr_DoctorLock[myDoctor]);

        //Take the prescription
        Myprescription = Prescription[myDoctor];

        cout << "\n\nPatient <-> Doctor\nPatientId: " <<patId <<"\nDoctorId: " <<myDoctor <<"\nPrescription: " <<Myprescription << "\nConsultancy Fees: " <<arr_ConsultancyFee[patId] <<"\nLeaving the doctor !!"<<endl;
        //cout << " \nPatient Id : " << patId << "got prescription: " << Myprescription << "from doctor :" << myDoctor << "\n";

        //Signal the Doctor that I have the prescrition and Leaving
         arr_DoctorCV[myDoctor]->Signal(arr_DoctorLock[myDoctor]);
         arr_DoctorLock[myDoctor]->Release();

         //printf("\nPatient Id: %d is leaving room\n",patId);
    }

         //cout<<" \nCASHIER STARTS\n\n";
    cashierLineLock->Acquire();

    int lineNumber = GetMinValue(lineSize, cashier);

    //cout << "\nLine Number" << lineNumber;
    if(lineSize[lineNumber]>0 || lineSize[lineNumber]==0)
    {
        //cout<<"\nPatient ID= "<<patientId<<"\nLine= "<<lineNumber<<"\nLineSize= "<<lineSize[lineNumber]<<"\n";
        //cout<<"\nAFTER lineNumber\n";

        lineSize[lineNumber]++;
        cout<<"\n\n***TEST CASE 6***\nDetails-\nPatient Id: "<<patientId<<"\nEntering Line: "<<lineNumber<<"\nLine Size: "<<lineSize[lineNumber]<<endl;
        //wait for the cashier to call
        cPatientCV[lineNumber]->Wait(cashierLineLock);
        //cout<<"\nPatient ID:"<< patId << "leaving queue!"<<endl;
        //After cashier calls me I will decrement
        lineSize[lineNumber]--;

        cashierLineLock->Release();

        interactionCashierLock[lineNumber]->Acquire();

        cashFlow[lineNumber] = myToken;


        //Signal the cashier that here is my token
        cashierCV[lineNumber]->Signal(interactionCashierLock[lineNumber]);

        //wait for the cashier to give the bill
        cashierCV[lineNumber]->Wait(interactionCashierLock[lineNumber]);

        //cout<<"Consultacy fees: "<<cashFlow[lineNumber]<<endl;

        //cashFlow[lineNumber] ; //temporary fee amount

        //Signals and say that here is the bill amount
        cashierCV[lineNumber]->Signal(interactionCashierLock[lineNumber]);

        cout<<"\n\nPatient <-> Cashier\nPatientId: " <<patId <<"\nCashierId: " <<lineNumber <<"\nConsulting Fees: "<<cashFlow[lineNumber] <<endl;
        interactionCashierLock[lineNumber]->Release();

        
    }

    //cout<<" \nPHARMACY CLERK STARTS\n\n";
    pharmaLineLock->Acquire();
        //One patient can enter the line at once
        //The lock on the line will control the flow of patient
        //to avoid confusion amongst patient

        //finds the shortest queue
    int pharmalineNumber = GetMinValue(linePharmaSize, clerks);


    if(linePharmaSize[pharmalineNumber]>0 || linePharmaSize[pharmalineNumber]==0)
    {
            //enters the queue
        linePharmaSize[pharmalineNumber]++;
        //cout<<"\nPatient ID= "<<patientId<<"\nLine= "<<pharmalineNumber<<"\nPharmaLineSize= "<<linePharmaSize[pharmalineNumber]<<"\n";
        cout<<"\n\n***TEST CASE 6***\nDetails-\nPatient Id: "<<patientId<<"\nEntering Line: "<<pharmalineNumber<<"\nLine Size: "<<linePharmaSize[pharmalineNumber]<<endl;

            //waiting for the clerk to call
        (patientCV[pharmalineNumber])->Wait(pharmaLineLock);

            //leaving the queue and releasing the held lock
        linePharmaSize[pharmalineNumber]--;

        pharmaLineLock->Release();

            //Acquire the exclusive lock to interact with the respective clerk
        interactionLock[pharmalineNumber]->Acquire();

        //load buffer with prescription
        pharmacyFlow[pharmalineNumber] = Myprescription;
            //signaling the clerk for interaction
        clerkCV[pharmalineNumber]->Signal(interactionLock[pharmalineNumber]);

            //waiting the clerk to respond
        clerkCV[pharmalineNumber]->Wait(interactionLock[pharmalineNumber]);
        //cout<<"\n**Cashier Patient Communication"<<endl;
            //get medicines and pay bill
        clerkCV[pharmalineNumber]->Signal(interactionLock[pharmalineNumber]);

        cout<<"\n\nPatient <-> Pharmacy Clerk\nPatientId: " <<patId <<"\nPharmacy Clerk Id: " <<pharmalineNumber << "\nPharmacy Amount: " <<pharmacyFlow[pharmalineNumber] <<endl;
        interactionLock[pharmalineNumber]->Release();

        cout<<"\n\nPatient Id: " <<patId <<" - Finished his visit to the hospital. Get Well Soon !!" <<endl;
        //cout << "/n########## Patient Id : " << patId << "Completed transaction.\n";

//        cout<<"\n\nEarning after Patients leave-\nPatient Id: "<<patId<<endl;
//            pharmacyTotalLock->Acquire();
//            cout<<"\n\n->Pharmacy Earning: " <<pharmacyTotal <<endl;
//            pharmacyTotalLock->Release();
//
//            cashierTotalLock->Acquire();
//            cout<<"\n\n->Cashier Earning: " <<cashierTotal <<endl;
//            cashierTotalLock->Release();
    }

}///End of patient.

//This function simulates the behaviour and characteristics of receptionist
//@input:  receptionistid : Id to recognize the receptionist.
//
void Receptionist(int receptionistId1){
    int receptionistId = receptionistId1;

    cout<<"\n\nThread Name: " << currentThread->getName() <<"\nReceptionist Id: " <<receptionistId <<endl;

    while(true){
        RecpLineLock->Acquire();
        
        //Check my line length
        if(arr_RecLineCount[receptionistId] > 0)
        {

            //Someone in my line
            arr_RecLineCV[receptionistId]->Signal(RecpLineLock);
           // cout << "Recep is signalling";
             
        }else{
            //I go on break
            //PUT CODE HERE
            RecBreakLock->Acquire();

            RecpLineLock->Release();
            cout<<"\n***TEST CASE 10***\nBreaks-\nReceptionist Id: "<<receptionistId<<"\nGoing for break as line size - "<<arr_RecLineCount[receptionistId]<<endl;
            //cout << "Receptionist :" << receptionistId << "Going on break as Line count is" << arr_RecLineCount[receptionistId] << "\n";
            RecbreakCV->Wait(RecBreakLock);
            RecBreakLock->Release();
            cout<<"\nBreaks-\nReceptionist Id: "<<receptionistId<<"\nWakes up !!"<<endl;
            //cout << "Receptionist :" << receptionistId << "Woken up \n";
            
            continue;
        }

  //      cout << "I am signalling the patient for interaction " << receptionistId << "\n";
        
        //A patient is coming to get a token number
        //I must wait for them to come to me
        RecepLock[receptionistId]->Acquire();
        RecpLineLock->Release();

       //cout << "Rec " << receptionistId <<  "going to wait \n" ;
        //I'm waiting on patient
        arr_RecCV[receptionistId]->Wait(RecepLock[receptionistId]);

        //I got woken up by Patient.Get a token
        tokenLock->Acquire();
        int newToken=(currentToken++);
        //cout << "Receptionis : " << receptionistId << "gave token number "<< newToken << "\n";
     //   RecToken[receptionistId]=newToken;
       
        tokenLock->Release();
       
        //Pass token to Patient
        RecToken[receptionistId]=newToken;

        //Signal Patient
        arr_RecCV[receptionistId]->Signal(RecepLock[receptionistId]);

        //Wait for Patient to get token
        arr_RecCV[receptionistId]->Wait(RecepLock[receptionistId]);

        //The patient has taken their token
        //Time for another patient
        RecepLock[receptionistId]->Release();

    }//end of while(true)
}///End of patient.


/*
 *
 * This function Siulates the behaviour of the DoorBoy
 *
 *
 */

void DoorBoy(int id){

    int DoorBoyId = id;
    int myDoc;
cout<<"\n\nThread Name: " << currentThread->getName() <<"\nDoorBoy Id: " <<id <<endl;
    while(true){
        
        // Door decides to work for the following doctor
        myDoc = GetDoctorForDoorBoy(Doctor_DB,numOfDoctors,DoorBoyId);
        //exit(0);
        //cout << "Doctor Id: " << myDoc << " for db :" << DoorBoyId << "\n";
        if(myDoc == -1){
            //Get a Doctor

            for(int i=0; i < numOfDoctors; i++){

                if(Doctor_DB[i] == -1 ){

                    //cout << Doctor_DB[i] <<"\n";
                    DoorBoyLock->Acquire();
                    Doctor_DB[i] = DoorBoyId;
                    DoorBoyLock->Release();
                    myDoc = i;


                    //cout << "DoorBoy( woken up) :" << DoorBoyId << "Assigned to doc :" <<  Doctor_DB[i] << "\n";
                    //Manager_DoorBoyLock->Release();
                    break;
                }


            }
        }

       
        //If my doctor is not on break then only I sent in the next patient
        if(arr_DoctorOnBreak[myDoc] == 1)
        {

//            cout << "MyDoctor is not on break\n";
//            exit(0);

               //wait for the doctor to signal   ***********************************
        

        //if there is someone in line and doctor is not on break **********
        if(arr_DoctorLineCount[myDoc] > 0)
        {
     
       // cout << DoorBoyId << "got the signal from doctor." << myDoc << "\n";
            Doctor_DoorBoyLock[myDoc]->Acquire();
        //tell doctor that I have patients, should I sent them
        Doctor_DoorBoyCV[myDoc]->Signal(Doctor_DoorBoyLock[myDoc]);

        //Wait till doctor tells to sent in.
        Doctor_DoorBoyCV[myDoc]->Wait(Doctor_DoorBoyLock[myDoc]);
        //cout<<"\n\nReady to see patients"<<endl;
        //exit(0);
        Doctor_DoorBoyLock[myDoc]->Release();
        DBLineLock->Acquire();
            //I signal the next patient in line to meet with the doctor
        cout<<"\n\n***TEST CASE 4*** \nDoor boy Signals patient to go ahead to meet doctor!!"<<endl;
            arr_DoctorLineCV[myDoc]->Signal(DBLineLock);
            
            //cout << "I have signaled the pateint to go to doctor:" << myDoc << "\n";

                //I will wait for the confirmation from the patient that he is going to see the doctor
            
            arr_DoctorLineCV[myDoc]->Wait(DBLineLock);
            DBLineLock->Release();

            //I will signal the Doctor that patient is coming
           // Doctor_DoorBoyCV[myDoc]->Signal(Doctor_DoorBoyLock[myDoc]);

        }

        //else there are no patients and doctor is not on break
        else {
            DBLineLock->Release();
             Doctor_DoorBoyLock[myDoc]->Release();
            //I will wait unitl manager signals me
            Manager_DoorBoyLock->Acquire();
            
             
            //cout << "Door boy Id" << DoorBoyId << "has zero line length. So Going to wait \n";

            //Doorboy Indicates to doctor that I am going on break.
            DoorBoyLock->Acquire();
            Doctor_DB[myDoc] = -1;
            DoorBoyLock->Release();

            cout<<"\n***TEST CASE 5***\nDoor Boy Id: "<<DoorBoyId<<"\nGoing for break as line size - "<<arr_DoctorLineCount[myDoc]<<endl;
            //exit(0);
            Manager_DoorboyCV->Wait(Manager_DoorBoyLock);
            Manager_DoorBoyLock->Release();
            //exit(0);
            cout<<"\nBreaks-\nDoor Boy Id: "<<DoorBoyId<<"\nWakes up !!"<<endl;

            //Assigning to a doctor

            for(int i=0; i < numOfDoctors; i++){

                if(Doctor_DB[i] == -1 && arr_DoctorLineCount[i] > 0){

                    //cout << Doctor_DB[i] <<"\n";
                    DoorBoyLock->Acquire();
                    Doctor_DB[i] = DoorBoyId;
                    DoorBoyLock->Release();


                  
                    //cout << "DoorBoy( woken up) :" << DoorBoyId << "Assigned to doc :" <<  Doctor_DB[i] << "\n";
                    //Manager_DoorBoyLock->Release();
                    break;
                }


            }
            
            
            continue;
         
        }

            //DBLineLock->Release();
            //Doctor_DoorBoyLock[myDoc]->Release();

            //cout << "Door Boy Id :" << DoorBoyId << "Got Confirmation about doctor id:" << myDoc << "\n";
        }
        //My Doctor is on break so i wait for him to come back.
        else{
            //cout << "Door boy id :" << DoorBoyId << " doctor ID :" << myDoc << "has gone to break, So I will wait";
            cout<<"\n\n***TEST CASE 8***\nDoctor Id: "<<myDoc<<"\nDoor boy waits for the doctor to return from break to send patient."<<endl;
            cout<<"\n\n***TEST CASE 9***\nDoctor Id: "<<myDoc<<"\nDoor boy never leaves the doctor when on break."<<endl;
            Doctor_DoorBoyLock[myDoc]->Acquire();
            Doctor_DoorBoyCV[myDoc]->Wait(Doctor_DoorBoyLock[myDoc]);
            Doctor_DoorBoyLock[myDoc]->Release();
        }
        

    }
}

/*
 *
 * This function Siulates the behaviour of the DoorBoy
 *
 *
 */

void Doctor(int id){
    int DocId = id;
    int myDoorBoy;
    cout<<"\n\nThread Name: " << currentThread->getName() <<"\nDoctor Id: " <<id <<endl;

    while(true){
       // cout << "Inside Doctor : " << id << "\n";

        //if(arr_DoctorLineCount[DocId] > 0){

        //Signal the door boy to send in the next patient

        Doctor_DoorBoyLock[DocId]->Acquire();
        
        // I wait for the Doorboy to tell me that he has patients
        Doctor_DoorBoyCV[DocId]->Wait(Doctor_DoorBoyLock[DocId]);
        cout<<"\n\nReceives signal from door boy"<<endl;
        //exit(0);
        //I signal the door boy to sent in the patients
        Doctor_DoorBoyCV[DocId]->Signal(Doctor_DoorBoyLock[DocId]);

        //$$$$$$$$$$$$$$$$$$$$$$$$$$$$
        //Wait for the doorboy to tell that patient is coming.
        //Doctor_DoorBoyCV[DocId]->Wait(Doctor_DoorBoyLock[DocId]);
        Doctor_DoorBoyLock[DocId]->Release(); 

        //cout << "Doc Id:" << DocId << "signalled the door boy to sent in the patient \n";

        arr_DoctorLock[DocId]->Acquire();

        //cout << "Patient did not came in for doctor ID " << DocId;
        //wait for the patient to come in.
        arr_DoctorCV[DocId]->Wait(arr_DoctorLock[DocId]);

        //cout << "Patient came in for doctor ID " << DocId;

        

        //After patient arrives docor starts consultation
        //simulating consultation
       // for(int i=0; i<5; i++)
         //   currentThread->Yield();

        ConsultancyLock->Acquire();
        arr_ConsultancyFee[Doctor_Token[DocId]] = rand() % (500 - 50 + 1) + 50;
        ConsultancyLock->Release();
        //Doctor gives prescription and consultancy fee
        Doc_PrescriptionLock->Acquire();

       // 
            //Tells the cashier the consulting fee.******************************
        Prescription[DocId] = rand() % (200 - 100 + 1) + 100;

        //cout << "\nDoctor Id: " << id << "gave the prescription" << Prescription[DocId] <<"\nConsulting fee:"; //<< arr_ConsultancyFee[Doctor_Token[DocId]]<<endl;
        Doc_PrescriptionLock->Release();

        

        //signal the patient that prescription is ready
        arr_DoctorCV[DocId]->Signal(arr_DoctorLock[DocId]);


        //wait for the patient to take prescription
        arr_DoctorCV[DocId]->Wait(arr_DoctorLock[DocId]);

        arr_DoctorLock[DocId]->Release();

        //Randomly Doctor decides to go to break
        if(GenerateRandomDoctorNumber(10,0)>0 && GenerateRandomDoctorNumber(10,0) <5)
        {
            //cout << "Doctor ID :" << DocId << "going on break\n";
            
            //informs the door boy that he is going to break.
            cout<<"\n\n***TEST CASE 7***\nDoctor Id: "<<DocId <<"\nIs on break based on a random number generated between 0 - 10"<<endl;
            DocBreakLock->Acquire();
            arr_DoctorOnBreak[DocId] = -1;
            DocBreakLock->Release();

            cout<<"\nBreaks-\nDoctor Id: "<<DocId<<"\nGoing for break!!"<<endl;

            for(int i=0; i<10; i++)
                currentThread->Yield();
            cout<<"\nBreaks-\nDoctor Id: "<<DocId<<"\nBack to Work!!"<<endl;

            //Signal the Doorboy that I am back from break.
             Doctor_DoorBoyLock[DocId]->Acquire();
            Doctor_DoorBoyCV[DocId]->Signal(Doctor_DoorBoyLock[DocId]);
            Doctor_DoorBoyLock[DocId]->Release();
            //cout << "Doctor ID : " << DocId << "signaled doorboy that I am back from break";
            
            
        }
        
            //Doctor Signals the DoorBoy to sent in the next patient.
            myDoorBoy = Doctor_DB[DocId];
            Doctor_DoorBoyLock[DocId]->Acquire();


            //If my door boy is on break, I will wait till someone comes
            if(myDoorBoy == -1)
            {
                //cout << "Doctor Id: " << DocId << "does not have a door boy, so going to wait \n";
                Doctor_DoorBoyCV[DocId]->Wait(Doctor_DoorBoyLock[DocId]);

                //cout << "Now Doctor Id: " << DocId << "has door boy " << Doctor_DB[DocId] << "\n";

            }

            //now I will signal my door boy to sent in the next patient.
                Doctor_DoorBoyCV[DocId]->Signal(Doctor_DoorBoyLock[DocId]);
                Doctor_DoorBoyLock[DocId]->Release();
        
        }


    //}

}

/*
 * This function simulates the behaviour of the cashier
 * 
 * 
 */

void PharmacyClerk(int clerkId)
{
    cout<<"\n\nThread Name: " << currentThread->getName() <<"\nPharmacy Clerk Id: " <<clerkId <<endl;
    while(true)
    {
        //acquire line lock to get the line value
        pharmaLineLock->Acquire();
        if(linePharmaSize[clerkId]>0)
        {
            //signal the patient in line to approach the counter and present the prescription
            patientCV[clerkId]->Signal(pharmaLineLock);
        }
        else
        {
//            //going to break
//            cout<<"\n\nClerk going to break!!"<<endl;
//            pharmaLineLock->Release();
//            //interactionLock[clerkId]->Acquire();
//            pharmacyControl[clerkId]->Wait(interactionLock[clerkId]);
//            //cout<<"This is impossible\n";
//            //interactionLock[clerkId]->Release();
//            cout<<"\nwaiting for patient or on break ";
//            continue;

            //going to break
            pharmaLineLock->Release();

            cout<<"\n\n***TEST CASE 10***\nBreaks-\nPharmacy Clerk Id: "<<clerkId<<"\nGoing for break as line size - "<<linePharmaSize[clerkId]<<endl;
            PharmacyBreakLock->Acquire();
            PharmacyBreakCV->Wait(PharmacyBreakLock);
            cout<<"\nBreaks-\nPharmacy Cler Id: "<<clerkId<<"\nWaker up !!"<<endl;
            PharmacyBreakLock->Release();
            //cout << clerkId << " Waking up \n";
            continue;
        }
        //acquire the lock to interact with the patient
        interactionLock[clerkId]->Acquire();
        pharmaLineLock->Release();

            //wait for patient to present the prescription
        clerkCV[clerkId]->Wait(interactionLock[clerkId]);
            //signal the patient for medicines and bill
        pharmacyFlow[clerkId] = rand() % (100 - 10 + 1) + 10;

        pharmacyTotalLock->Acquire();
        pharmacyTotal+=pharmacyFlow[clerkId];
        pharmacyTotalLock->Release();

        clerkCV[clerkId]->Signal(interactionLock[clerkId]);
            //wait for the patient to pay the amount
        clerkCV[clerkId]->Wait(interactionLock[clerkId]);
            //total amonunt collected
        interactionLock[clerkId]->Release();

    }
}


void Cashier(int cashierId)
{
    cout<<"\n\nThread Name: " << currentThread->getName() <<"\nCashier Id: " <<cashierId <<endl;
    while(true)
    {
        // Acquire line lock to evict a patient for interaction
        // This will control the outflow of patients
        cashierLineLock->Acquire();

        //if the line has patient then signal them to come ahead for interaction
        if(lineSize[cashierId]>0)
        {
            cPatientCV[cashierId]->Signal(cashierLineLock);
                //signaling patient who is in sleep.
        }
        else
        {
            //if the line doesn't have any patients the Cashier can go for a break/
            //he/she must be called back if any patient enters the line.
            cashierLineLock->Release();
           CashierBreakLock->Acquire();
            
            cout<<"\n\n***TEST CASE 10***\nBreaks-\nCashier Id: "<<cashierId<<"\nGoing for break as line size - "<<lineSize[cashierId]<<endl;
            CashierBreakCV->Wait(CashierBreakLock);
            cout<<"\nBreaks-\nCashier Id: "<<cashierId<<"\nWakes up !!"<<endl;
            CashierBreakLock->Release(); 
            

            //cout<<"\nCashier:"<<cashierId<<" Woken up \n\n\n";
            continue;
//            cashierLineLock->Release();
//            cout<<" Cashier is going on break"<< cashierId << endl;
//            interactionCashierLock[cashierId]->Acquire();
//            cashierControl[cashierId]->Wait(interactionCashierLock[cashierId]);
//            //interactionCashierLock[cashierId]->Release();
//            cout<<"\nWaiting for patients or on break";
//            interactionCashierLock[cashierId]->Release();
//            continue;
        }

        //after signalling the patient the cashier acquires the interaction lock
        interactionCashierLock[cashierId]->Acquire();

        //the cashier leaves the line control lock this will allow others to use the queue for patients
        cashierLineLock->Release();

        //The cashier waits for the patient to respond
        cashierCV[cashierId]->Wait(interactionCashierLock[cashierId]);

        //Patient responds with his token number.
        //cout<<"Token: "<<cashFlow[cashierId]<<endl;

        // the cashier give the infromation about the fees ect through the shared buffer ie. cashFlow
        ConsultancyLock->Acquire();
        cashFlow[cashierId] = arr_ConsultancyFee[cashFlow[cashierId]]; //temporary variable for fees
        ConsultancyLock->Release();

        cashierTotalLock->Acquire();
        cashierTotal += cashFlow[cashierId];
        cashierTotalLock->Release();

        //Cashier signals the patient that the information is furnished
        cashierCV[cashierId]->Signal(interactionCashierLock[cashierId]);

        //Cashier waits for the patient to give the money
        cashierCV[cashierId]->Wait(interactionCashierLock[cashierId]);

        //The amount is recieved by the Cashier
       // cout<<"Fees Received: "<<cashFlow[cashierId]<<endl;

        //This will releive his interaction with the patient
        interactionCashierLock[cashierId]->Release();
    }
}


void Hospital_Manager(int HM_id){
    int count, countpat, countcash, countpharma;
    countpat = 0;
    cout<<"\n\nThread Name: " << currentThread->getName() <<"\nHospital Manager" <<endl;

    while(true){
        
      
       // cout<<"\nHospital Manager acquired lock \n";

RecBreakLock->Acquire();
count = 0;
        if(Num_of_receptionist==0)
        {
            cout<<"\n\n***TEST CASE 2***\nStopping service as receptionist are on Strike!!"<<endl;
            exit(0);
        }
        for(int i=0;i<Num_of_receptionist;i++){
            count+=arr_RecLineCount[i];
        }
        
        if(count>0){
            cout<<"\n\nHospital Manager-\nBroadcasting to all recptionists!!";
            RecbreakCV->Broadcast(RecBreakLock);
            RecBreakLock->Release();
            
        }else{
            RecBreakLock->Release();
        }
         Manager_DoorBoyLock->Acquire();
        countpat=0;
        for(int i=0; i<numOfDoctors; i++)
        {
            countpat += arr_DoctorLineCount[i];

        }
          
        //If there are any patients waiting in line signal
        if(countpat >= 1){
            cout << "\n\nHospital Manager-\nBroadcasting to all doorboys!!";
            //reset the count
            //countpat = 0;
        
            Manager_DoorboyCV->Broadcast(Manager_DoorBoyLock);
            Manager_DoorBoyLock->Release();

        }else
        {
            Manager_DoorBoyLock->Release();
        }

        countcash = 0;

        CashierBreakLock->Acquire();
        //count number of patients in the cashier's Line
        for(int i=0; i<cashier; i++){
            countcash += lineSize[i];
        }
            if(countcash > 0){
                cout << "\n\nHospital Manager-\nBroadcasting to all cashiers!!";
                CashierBreakCV->Broadcast(CashierBreakLock);
                CashierBreakLock->Release();
            }else{
                CashierBreakLock->Release();
            }

            //count_cashier += lineSize[i];
            //cout<<"count_cashier= "<<count_cashier<<endl;

           countpharma = 0;

        PharmacyBreakLock->Acquire();
        //count number of patients in the cashier's Line
        for(int i=0; i<clerks; i++){
            countpharma += lineSize[i];
        }
            if(countpharma > 0){
                cout << "\n\nHospital Manager-\nBroadcasting to all pharmacy clerks!!";
               PharmacyBreakCV->Broadcast(PharmacyBreakLock);
                PharmacyBreakLock->Release();
            }else{
                PharmacyBreakLock->Release();
            }

//        countpharma = 0;
//
//        for(int i=0; i<clerks; i++){
//            countpharma += linePharmaSize[i];
//            if(linePharmaSize[i] > 0){
//                interactionLock[i]->Acquire();
//                pharmacyControl[i]->Signal(interactionLock[i]);
//                interactionLock[i]->Release();
//            }
//
//            else
//            {
//            //    interactionLock[i]->Release();
//            //}
//
//            //count_cashier += lineSize[i];
//            //cout<<"count_cashier= "<<count_cashier<<endl;
//        }
//        }

        

        if( count+countpat+countcash+countpharma == 0){
            //cout << "there are no patients in line :" << countpat;
            //  Manager_DoorBoyLock->Release();
              //RecBreakLock->Release();
            //exit(0);
            pharmacyTotalLock->Acquire();
            cout<<"\n\n->Pharmacy Earning: " <<pharmacyTotal <<endl;
            pharmacyTotalLock->Release();

            cashierTotalLock->Acquire();
            cout<<"\n\n->Cashier Earning: " <<cashierTotal <<endl;
            cashierTotalLock->Release();
            break;

        }
        else{
            //cout << "going to continue";
          //  Manager_DoorBoyLock->Release();
           // RecBreakLock->Release();
            continue;}


    }
}



//This function takes in an array and returns the index of the smallest value

int GetMinValue(int arr[],int size){
    int temp_val = 1000;
    int temp_index = 1000;
    
    for(int arr_min=0;arr_min < size; arr_min++)
    {
        if(arr[arr_min] < temp_val)
        {
            temp_val = arr[arr_min];
            temp_index = arr_min;

        }
        //printf("\ntemp_index=%d",temp_index);

    }

    return temp_index;

}

//This functions generates a random number between the hign and low limits
// inclusive of high and low.

int GenerateRandomDoctorNumber(int high, int low){

    return rand() % (high - low + 1) + low;

}

//This funtions gives the doctor to which the door boy responds

int GetDoctorForDoorBoy(int arr[], int size, int DB_ID){

    for(int i=0; i<size ; i++)
    {
        if(arr[i] == DB_ID)
            return i;
    }
    return -1;

}

void InitializeManager(){
    Manager_DoorBoyLock = new Lock("ManagerDBLock");
    Manager_DoorboyCV = new Condition("ManagerDoorBoyCV");

}